package org.eclipse.refactoring.field;

import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.core.runtime.SubProgressMonitor;
import org.eclipse.jdt.core.Flags;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IField;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IMember;
import org.eclipse.jdt.core.IPackageFragment;
import org.eclipse.jdt.core.IPackageFragmentRoot;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaConventions;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.dom.AST;
import org.eclipse.jdt.core.dom.ASTNode;
import org.eclipse.jdt.core.dom.ASTParser;
import org.eclipse.jdt.core.dom.ASTRequestor;
import org.eclipse.jdt.core.dom.ASTVisitor;
import org.eclipse.jdt.core.dom.Assignment;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.core.dom.Expression;
import org.eclipse.jdt.core.dom.ExpressionStatement;
import org.eclipse.jdt.core.dom.IBinding;
import org.eclipse.jdt.core.dom.ITypeBinding;
import org.eclipse.jdt.core.dom.IVariableBinding;
import org.eclipse.jdt.core.dom.InfixExpression;
import org.eclipse.jdt.core.dom.MethodDeclaration;
import org.eclipse.jdt.core.dom.MethodInvocation;
import org.eclipse.jdt.core.dom.NodeFinder;
import org.eclipse.jdt.core.dom.PostfixExpression;
import org.eclipse.jdt.core.dom.SimpleName;
import org.eclipse.jdt.core.dom.Statement;
import org.eclipse.jdt.core.dom.VariableDeclarationFragment;
import org.eclipse.jdt.core.dom.VariableDeclarationStatement;
import org.eclipse.jdt.core.dom.rewrite.ASTRewrite;
import org.eclipse.jdt.core.dom.rewrite.ImportRewrite;
import org.eclipse.jdt.core.search.IJavaSearchConstants;
import org.eclipse.jdt.core.search.IJavaSearchScope;
import org.eclipse.jdt.core.search.SearchEngine;
import org.eclipse.jdt.core.search.SearchMatch;
import org.eclipse.jdt.core.search.SearchParticipant;
import org.eclipse.jdt.core.search.SearchPattern;
import org.eclipse.jdt.core.search.SearchRequestor;
import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
import org.eclipse.jdt.internal.core.Initializer;
import org.eclipse.jdt.internal.core.ResolvedSourceField;
import org.eclipse.jdt.internal.core.ResolvedSourceMethod;
import org.eclipse.jdt.ui.JavaElementLabels;
import org.eclipse.ltk.core.refactoring.Change;
import org.eclipse.ltk.core.refactoring.ChangeDescriptor;
import org.eclipse.ltk.core.refactoring.CompositeChange;
import org.eclipse.ltk.core.refactoring.Refactoring;
import org.eclipse.ltk.core.refactoring.RefactoringChangeDescriptor;
import org.eclipse.ltk.core.refactoring.RefactoringStatus;
import org.eclipse.ltk.core.refactoring.TextFileChange;
import org.eclipse.text.edits.MalformedTreeException;
import org.eclipse.text.edits.MultiTextEdit;
import org.eclipse.text.edits.TextEdit;

public class PrefixRefactorRefactoring extends Refactoring {

	private static final String CLASS = "class";

	private static final String REFERENCES = "references";

	private static final String PACKAGE = "package";

	private static final String FIELD_PREFIX = "m";

	private static final String PARAMETER_PREFIX = "p";

	private static final String LOCAL_VAR_PREFIX = "l";

	private static final String STATIC_FIELD_PREFIX = "g";

	private Map<ICompilationUnit, TextFileChange> mChanges = null;

	ICompilationUnit mICompilationUnit = null;

	List<ICompilationUnit> mICompilationUnits = null;

	IPackageFragment mIPackageFragment = null;

	// String mName = null;

	boolean mUpdateReferences = true;

	@Override
	public RefactoringStatus checkFinalConditions(IProgressMonitor monitor)
			throws CoreException, OperationCanceledException {
		final RefactoringStatus status = new RefactoringStatus();
		try {
			monitor.beginTask("Checking preconditions...", 2);
			mChanges = new LinkedHashMap<ICompilationUnit, TextFileChange>();

			final Map<IJavaProject, Set<ICompilationUnit>> projects = new HashMap<IJavaProject, Set<ICompilationUnit>>();
			final Map<ICompilationUnit, Collection<SearchMatch>> matchesPerUnit = new HashMap<ICompilationUnit, Collection<SearchMatch>>();
			final Map<IField, Collection<ICompilationUnit>> lReferencingUnits = new HashMap<IField, Collection<ICompilationUnit>>();
			final List<IField> lFieldList = new ArrayList<IField>();

			for (ICompilationUnit lICompilationUnit : mICompilationUnits)
				// Go through all fields
				for (IType lIType : lICompilationUnit.getAllTypes()) {
					for (final IField lIField : lIType.getFields()) {
						ICompilationUnit lCompilationUnit = lIField
								.getCompilationUnit();

						if (hasToRenammeField(lIField)) {
							lFieldList.add(lIField);
							final Set<SearchMatch> invocations = new HashSet<SearchMatch>();

							// Find method references
							if (mUpdateReferences) {
								IJavaSearchScope scope = SearchEngine
										.createJavaSearchScope(new IJavaElement[] { lICompilationUnit
												.getJavaProject() });
								SearchPattern pattern = SearchPattern
										.createPattern(
												lIField,
												IJavaSearchConstants.REFERENCES,
												SearchPattern.R_EXACT_MATCH);
								SearchEngine engine = new SearchEngine();
								engine.search(
										pattern,
										new SearchParticipant[] { SearchEngine
												.getDefaultSearchParticipant() },
										scope,
										new SearchRequestor() {

											@Override
											public void acceptSearchMatch(
													SearchMatch match)
													throws CoreException {
												if (match.getAccuracy() == SearchMatch.A_ACCURATE
														&& !match
																.isInsideDocComment()) {
													Object lMatchElement = match
															.getElement();
													if (isConsideredMatch(lMatchElement)) {
														invocations.add(match);
													}
												}
											}

											private boolean isConsideredMatch(
													Object pMatch) {
												return pMatch instanceof ResolvedSourceMethod
														|| pMatch instanceof ResolvedSourceField
														|| pMatch instanceof Initializer;
											}
										},
										new SubProgressMonitor(
												monitor,
												1,
												SubProgressMonitor.SUPPRESS_SUBTASK_LABEL));
							}

							if (matchesPerUnit.get(lCompilationUnit) == null) {
								matchesPerUnit.put(lCompilationUnit,
										new ArrayList<SearchMatch>());
							}
							if (lReferencingUnits.get(lIField) == null) {
								lReferencingUnits.put(lIField,
										new ArrayList<ICompilationUnit>());
							}

							// For all references, add a new entry into the map
							if (mUpdateReferences) {
								for (SearchMatch lMatch : invocations) {
									Object lMatchElement = lMatch.getElement();
									if (lMatchElement instanceof IMember) {
										ICompilationUnit lMatchUnit = ((IMember) lMatchElement)
												.getCompilationUnit();
										if (lMatchUnit != null) {
											if (!lReferencingUnits.get(lIField)
													.contains(lMatchUnit)) {
												lReferencingUnits.get(lIField)
														.add(lMatchUnit);
											}
											Collection<SearchMatch> lMatches = matchesPerUnit
													.get(lMatchUnit);
											if (lMatches == null) {
												lMatches = new ArrayList<SearchMatch>();
												matchesPerUnit.put(lMatchUnit,
														lMatches);
											}
											lMatches.add(lMatch);
										}
									}
								}
							}

							// Build a map containing projects (keys) where a
							// reference has been found
							// For each project, map value is the collection of
							// compilation unit where a reference has been found

							for (ICompilationUnit unit : matchesPerUnit
									.keySet()) {
								IJavaProject project = unit.getJavaProject();
								if (project != null) {
									Set<ICompilationUnit> collection = projects
											.get(project);
									if (collection == null) {
										collection = new HashSet<ICompilationUnit>();
										projects.put(project, collection);
									}
									collection.add(unit);
								}
							}

						}
					}
				}

			// Create the requestor for changing compilation unit
			ASTRequestor requestors = new ASTRequestor() {

				@Override
				public void acceptAST(ICompilationUnit source,
						CompilationUnit ast) {
					try {
						rewriteCompilationUnit(this, source, lReferencingUnits,
								matchesPerUnit, ast, status, lFieldList);

						// ASTRewrite astRewrite =
						// ASTRewrite.create(ast.getAST());
						// ast.accept(new MethodVisitor(astRewrite));

						// ImportRewrite importRewrite = ImportRewrite.create(
						// source, true);
						// rewriteAST(source, astRewrite, importRewrite);
					} catch (JavaModelException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					} catch (CoreException exception) {
						RefactoringPlugin.log(exception);
					}
					// ImportRewrite importRewrite;
					// try {
					// importRewrite = ImportRewrite.create(source, true);
					// rewriteAST(source, astRewrite, importRewrite);
					// } catch (JavaModelException e) {
					// // TODO Auto-generated catch block
					// e.printStackTrace();
					// }
				}
			};

			IProgressMonitor subMonitor = new SubProgressMonitor(monitor, 1);

			try {
				final Set<IJavaProject> set = projects.keySet();
				subMonitor.beginTask("Compiling source...", set.size());

				for (IJavaProject project : set) {
					ASTParser parser = ASTParser.newParser(AST.JLS3);
					parser.setProject(project);
					parser.setResolveBindings(true);
					Set<ICompilationUnit> collection = projects.get(project);
					parser.createASTs(collection
							.toArray(new ICompilationUnit[collection.size()]),
							new String[0], requestors, new SubProgressMonitor(
									subMonitor, 1));
				}

			} finally {
				subMonitor.done();
			}

			// final ArrayList<IMethod> lIMethods = new ArrayList<IMethod>();

			// Go through all fields
			// for (IType lIType : mICompilationUnit.getAllTypes()) {
			// for (final IMethod lIMethod : lIType.getMethods()) {
			// // lIMethods.add(lIMethod);
			// // String lSignature = lIMethod.getSignature();
			// // System.out.println(lSignature);
			// // IMethodBinding methodBinding = null;
			// // ASTRequestor requestors= new ASTRequestor() {
			// //
			// // @Override
			// // public void acceptAST(ICompilationUnit source, CompilationUnit
			// ast) {
			// //// try {
			// //// } catch (CoreException exception) {
			// //// RefactoringPlugin.log(exception);
			// //// }
			// // }
			// //
			// // };
			//
			//
			//
			// }
			// Create the requestor for changing compilation unit
			// ASTRequestor requestors = new ASTRequestor() {
			//
			// @Override
			// public void acceptAST(ICompilationUnit source,
			// CompilationUnit ast) {
			// try {
			// // rewriteMethodParameters(this, source, lIMethods, ast, status);
			// rewriteCompilationUnit(this, source,
			// lReferencingUnits, matchesPerUnit, ast, status, lFieldList);
			// } catch (CoreException exception) {
			// RefactoringPlugin.log(exception);
			// }
			// }
			// };
			//
			// IProgressMonitor subMonitor = new SubProgressMonitor(monitor, 1);
			//
			// try {
			// final Set<IJavaProject> set = projects.keySet();
			// subMonitor.beginTask("Compiling source...", set.size());
			//
			// for (IJavaProject project : set) {
			// ASTParser parser = ASTParser.newParser(AST.JLS3);
			// parser.setProject(project);
			// parser.setResolveBindings(true);
			// Set<ICompilationUnit> collection = projects
			// .get(project);
			// parser.createASTs(
			// collection
			// .toArray(new ICompilationUnit[collection
			// .size()]), new String[0],
			// requestors, new SubProgressMonitor(subMonitor,
			// 1));
			// }
			//
			// } finally {
			// subMonitor.done();
			// }

		} finally {
			monitor.done();
		}
		return status;
	}

	// private void rewriteMethodParameters(
	// ASTRequestor astRequestor,
	// ICompilationUnit source, ArrayList<IMethod> lIMethods,
	// CompilationUnit node, RefactoringStatus status) {
	//
	//
	// for (IMethod lIMethod : lIMethods) {
	// ASTRewrite astRewrite = ASTRewrite.create(node.getAST());
	// ImportRewrite importRewrite = ImportRewrite.create(node, true);
	// IBinding[] bindings = astRequestor.createBindings(new String[] {
	// lIMethod.getKey()});
	// IMethodBinding lMethodBinding = null;
	// if (bindings[0] instanceof IMethodBinding) {
	// lMethodBinding= (IMethodBinding) bindings[0];
	// if (lMethodBinding == null)
	// return;
	// ITypeBinding[] lTypeBindings = lMethodBinding.getParameterTypes();
	// for (ITypeBinding lTypeBinding : lTypeBindings) {
	// String lParameterName = lTypeBinding.getName();
	// if (hasToBeRenammed(lParameterName, PARAMETER_PREFIX)) {
	//
	// }
	// }
	// AST ast = node.getAST();
	//
	// // Method declaration
	// MethodDeclaration lMethodDeclaration = ast
	// .newMethodDeclaration();
	// lMethodDeclaration.setName(ast.newSimpleName(lIMethod.getElementName()));
	// // fragment.setFlags(pIField.getFlags());
	//
	// ASTNode lMethodNode = node.findDeclaringNode(lMethodBinding);
	//
	// if (lMethodNode instanceof MethodRef) {
	// MethodRef lMethodRef = (MethodRef) lMethodNode;
	//
	//
	// }
	//
	// astRewrite.replace(lMethodNode, lMethodDeclaration, null);
	// }
	// }
	//
	// }

	private boolean hasToBeRenammed(String pName, String pPrefix) {
		boolean lResult = true;

		if (pName.startsWith(pPrefix)) {
			if (pName.length() > 1) {
				String lSecondChar = String.valueOf(pName.charAt(1));
				if (lSecondChar.equals(lSecondChar.toUpperCase())) {
					lResult = false;
				}
			}
		}

		return lResult;
	}

	private boolean hasToRenammeField(IField pIField) {
		String lFieldName = pIField.getElementName();
		try {

			return !pIField.getDeclaringType().isEnum()
					&& !pIField.getDeclaringType().isInterface()
					&& !lFieldName.equals("serialVersionUID")
					&& ((Flags.isStatic(pIField.getFlags())
							&& !Flags.isFinal(pIField.getFlags()) && hasToBeRenammed(
								lFieldName, STATIC_FIELD_PREFIX)) || (!Flags
							.isStatic(pIField.getFlags()) && hasToBeRenammed(
							lFieldName, FIELD_PREFIX)));
		} catch (JavaModelException e) {
			e.printStackTrace();
			return false;
		}
	}

	@Override
	public RefactoringStatus checkInitialConditions(IProgressMonitor monitor)
			throws CoreException, OperationCanceledException {
		RefactoringStatus status = new RefactoringStatus();
		try {
			monitor.beginTask("Checking preconditions...", 1);
			if (mICompilationUnit == null && mIPackageFragment == null)
				status.merge(RefactoringStatus
						.createFatalErrorStatus("Neither ICompilationUnit nor IPackageFragement has not been specified."));
			else if (mICompilationUnit != null && !mICompilationUnit.exists())
				status.merge(RefactoringStatus
						.createFatalErrorStatus(MessageFormat.format(
								"ICompilationUnit ''{0}'' does not exist.",
								new Object[] { mICompilationUnit
										.getElementName() })));
			else if (mIPackageFragment != null && !mIPackageFragment.exists())
				status.merge(RefactoringStatus
						.createFatalErrorStatus(MessageFormat.format(
								"IPackageFragment ''{0}'' does not exist.",
								new Object[] { mIPackageFragment
										.getElementName() })));
			else if (mICompilationUnit != null
					&& !mICompilationUnit.isStructureKnown())
				status.merge(RefactoringStatus.createFatalErrorStatus(MessageFormat
						.format("Compilation unit ''{0}'' contains compile errors.",
								new Object[] { mICompilationUnit
										.getElementName() })));
			else if (mIPackageFragment != null
					&& !mIPackageFragment.isStructureKnown())
				status.merge(RefactoringStatus.createFatalErrorStatus(MessageFormat
						.format("Package fragment ''{0}'' contains compile errors.",
								new Object[] { mIPackageFragment
										.getElementName() })));
		} finally {
			monitor.done();
		}
		return status;
	}

	// private RefactoringStatus checkMethodName(String name, IStatus status) {
	// RefactoringStatus result= new RefactoringStatus();
	//		if ("".equals(name)) //$NON-NLS-1$
	// return RefactoringStatus.createFatalErrorStatus("Choose a name.");
	//
	// if (status.isOK())
	// return result;
	//
	// switch (status.getSeverity()) {
	// case IStatus.ERROR:
	// return RefactoringStatus.createFatalErrorStatus(status.getMessage());
	// case IStatus.WARNING:
	// return RefactoringStatus.createWarningStatus(status.getMessage());
	// case IStatus.INFO:
	// return RefactoringStatus.createInfoStatus(status.getMessage());
	// default: // no nothing
	// return new RefactoringStatus();
	// }
	// }

	// private RefactoringStatus checkClassName(String name, IStatus status) {
	// RefactoringStatus result = new RefactoringStatus();
	//		if ("".equals(name)) //$NON-NLS-1$
	// return RefactoringStatus.createFatalErrorStatus("Choose a name.");
	//
	// if (status.isOK())
	// return result;
	//
	// switch (status.getSeverity()) {
	// case IStatus.ERROR:
	// return RefactoringStatus
	// .createFatalErrorStatus(status.getMessage());
	// case IStatus.WARNING:
	// return RefactoringStatus.createWarningStatus(status.getMessage());
	// case IStatus.INFO:
	// return RefactoringStatus.createInfoStatus(status.getMessage());
	// default: // no nothing
	// return new RefactoringStatus();
	// }
	// }

	private RefactoringStatus convertIStatus(IStatus status) {
		RefactoringStatus result = new RefactoringStatus();
		if (status == null) //$NON-NLS-1$
			return RefactoringStatus
					.createFatalErrorStatus("Choose a Java file or a package.");

		if (status.isOK())
			return result;

		switch (status.getSeverity()) {
		case IStatus.ERROR:
			return RefactoringStatus
					.createFatalErrorStatus(status.getMessage());
		case IStatus.WARNING:
			return RefactoringStatus.createWarningStatus(status.getMessage());
		case IStatus.INFO:
			return RefactoringStatus.createInfoStatus(status.getMessage());
		default: // no nothing
			return new RefactoringStatus();
		}
	}

	@Override
	public Change createChange(IProgressMonitor monitor) throws CoreException,
			OperationCanceledException {
		try {
			monitor.beginTask("Creating change...", 1);
			final Collection<TextFileChange> changes = mChanges.values();
			CompositeChange change = new CompositeChange(getName(),
					changes.toArray(new Change[changes.size()])) {

				@Override
				public ChangeDescriptor getDescriptor() {

					String project = mICompilationUnits.get(0).getJavaProject()
							.getElementName();
					String description = null;
					if (mICompilationUnit != null) {
						description = MessageFormat.format(
								"Renaming field on ''{0}''",
								new Object[] { mICompilationUnit
										.getElementName() });
					} else {
						description = MessageFormat.format(
								"Renaming field on ''{0}''",
								new Object[] { mIPackageFragment
										.getElementName() });
					}
					String classLabel = null;

					if (mICompilationUnit != null) {
						classLabel = JavaElementLabels.getTextLabel(
								mICompilationUnit,
								JavaElementLabels.ALL_FULLY_QUALIFIED);
					} else {
						classLabel = JavaElementLabels.getTextLabel(
								mIPackageFragment,
								JavaElementLabels.ALL_FULLY_QUALIFIED);
					}
					// String typeLabel= JavaElementLabels.getTextLabel(fType,
					// JavaElementLabels.ALL_FULLY_QUALIFIED);
					String comment = MessageFormat.format(
							"Renaming field on ''{0}''",
							new Object[] { classLabel });
					Map<String, String> arguments = new HashMap<String, String>();
					if (mICompilationUnit != null) {
						arguments.put(CLASS,
								mICompilationUnit.getHandleIdentifier());
					}
					if (mIPackageFragment != null) {
						arguments.put(PACKAGE,
								mIPackageFragment.getHandleIdentifier());
					}
					// arguments.put(TYPE, fType.getHandleIdentifier());
					// arguments.put(NAME, fName);
					arguments.put(REFERENCES, Boolean
							.valueOf(mUpdateReferences).toString());
					return new RefactoringChangeDescriptor(
							new PrefixRefactorDescriptor(project, description,
									comment, arguments));
				}
			};
			return change;
		} finally {
			monitor.done();
		}
	}

	// public String getMethodName() {
	// return mName;
	// }

	@Override
	public String getName() {
		return "Refactor Fields";
	}

	public RefactoringStatus initialize(Map arguments) {
		RefactoringStatus status = new RefactoringStatus();
		String value = (String) arguments.get(CLASS);
		if (value != null)
			setCompilationUnit((ICompilationUnit) JavaCore.create(value));
		// value= (String) arguments.get(TYPE);
		// if (value != null)
		// setDeclaringType((IType) JavaCore.create(value));
		// value= (String) arguments.get(NAME);
		// if (value != null)
		// setMethodName(value);
		value = (String) arguments.get(REFERENCES);
		if (value != null)
			setUpdateReferences(Boolean.valueOf(value).booleanValue());

		value = (String) arguments.get(PACKAGE);
		if (value != null)
			setPackageFragment((IPackageFragment) JavaCore.create(value));

		return status;
	}

	private boolean isEmptyEdit(TextEdit edit) {
		return edit.getClass() == MultiTextEdit.class && !edit.hasChildren();
	}

	private void rewriteAST(ICompilationUnit unit, ASTRewrite astRewrite,
			ImportRewrite importRewrite) {
		try {
			MultiTextEdit edit = new MultiTextEdit();
			TextEdit astEdit = astRewrite.rewriteAST();

			if (!isEmptyEdit(astEdit))
				edit.addChild(astEdit);
			TextEdit importEdit = importRewrite
					.rewriteImports(new NullProgressMonitor());
			if (!isEmptyEdit(importEdit))
				edit.addChild(importEdit);
			if (isEmptyEdit(edit))
				return;

			TextFileChange change = mChanges.get(unit);
			if (change == null) {
				change = new TextFileChange(unit.getElementName(),
						(IFile) unit.getResource());
				change.setTextType("java");
				change.setEdit(edit);
			} else
				change.getEdit().addChild(edit);

			mChanges.put(unit, change);
		} catch (MalformedTreeException exception) {
			RefactoringPlugin.log(exception);
		} catch (IllegalArgumentException exception) {
			RefactoringPlugin.log(exception);
		} catch (CoreException exception) {
			RefactoringPlugin.log(exception);
		}
	}

	protected void rewriteCompilationUnit(ASTRequestor requestor,
			ICompilationUnit unit,
			Map<IField, Collection<ICompilationUnit>> lReferencingUnits,
			Map<ICompilationUnit, Collection<SearchMatch>> units,
			CompilationUnit node, RefactoringStatus status,
			List<IField> lFieldList) throws CoreException {
		ASTRewrite astRewrite = ASTRewrite.create(node.getAST());
		ImportRewrite importRewrite = ImportRewrite.create(node, true);

		for (IField lIField : lFieldList) {
			if (unit.equals(lIField.getDeclaringType().getCompilationUnit())) {
				rewriteDeclaringType(requestor, astRewrite, importRewrite,
						unit, node, lIField);
			}
			if (mUpdateReferences) {
				for (ICompilationUnit lICompilationUnit : lReferencingUnits
						.get(lIField)) {
					for (final Iterator<SearchMatch> iterator = units.get(
							lICompilationUnit).iterator(); iterator.hasNext();) {
						SearchMatch match = iterator.next();
						if (match.getAccuracy() == SearchMatch.A_ACCURATE) {
							ASTNode result = NodeFinder.perform(node,
									match.getOffset(), match.getLength());
							if (result instanceof SimpleName
									&& ((SimpleName) result).getIdentifier()
											.equals(lIField.getElementName())) {
								status.merge(rewriteFieldAccess(requestor,
										astRewrite, importRewrite, lIField,
										(SimpleName) result));
							}
						}
					}
				}
			}
		}
		rewriteAST(unit, astRewrite, importRewrite);
	}

	private void rewriteDeclaringType(ASTRequestor requestor,
			ASTRewrite astRewrite, ImportRewrite importRewrite,
			ICompilationUnit unit, CompilationUnit node, IField pIField)
			throws CoreException {

		IVariableBinding lVariableBinding = null;
		ITypeBinding lDeclaringType = null;
		IBinding[] bindings = requestor.createBindings(new String[] { pIField
				.getKey() });
		if (bindings[0] instanceof IVariableBinding) {
			lVariableBinding = (IVariableBinding) bindings[0];
			if (lVariableBinding != null && lVariableBinding.isField()) {
				lDeclaringType = lVariableBinding.getDeclaringClass();
			}
		}

		if (lVariableBinding == null || lDeclaringType == null)
			return;

		AST ast = node.getAST();

		// Field declaration
		VariableDeclarationFragment fragment = ast
				.newVariableDeclarationFragment();

		fragment.setName(ast.newSimpleName(getRenammedField(pIField)));
		// fragment.setFlags(pIField.getFlags());

		ASTNode lVariableNode = node.findDeclaringNode(lVariableBinding);

		if (lVariableNode instanceof VariableDeclarationFragment) {
			VariableDeclarationFragment lVariableDeclarationFragment = (VariableDeclarationFragment) lVariableNode;
			Expression lExpression = lVariableDeclarationFragment
					.getInitializer();

			if (lExpression != null) {
				fragment.setInitializer((Expression) astRewrite
						.createCopyTarget(lExpression));
			}
		}

		astRewrite.replace(lVariableNode, fragment, null);

	}

	private String getRenammedField(IField pIField) throws JavaModelException {
		String lNewFieldName = null;
		if (Flags.isStatic(pIField.getFlags())) {
			lNewFieldName = getRefactoredName(pIField.getElementName(),
					STATIC_FIELD_PREFIX);
		} else {
			lNewFieldName = getRefactoredName(pIField.getElementName(),
					FIELD_PREFIX);
		}
		return lNewFieldName;
	}

	private RefactoringStatus rewriteFieldAccess(ASTRequestor requestor,
			ASTRewrite astRewrite, ImportRewrite importRewrite, IField pIField,
			SimpleName result) throws JavaModelException {
		RefactoringStatus status = new RefactoringStatus();

		ITypeBinding declaringBinding = null;
		IBinding[] bindings = requestor.createBindings(new String[] { pIField
				.getDeclaringType().getKey() });
		if (bindings[0] instanceof ITypeBinding) {
			declaringBinding = (ITypeBinding) bindings[0];
		}

		if (declaringBinding == null)
			return status;

		AST ast = result.getAST();

		SimpleName newSimpleName = ast.newSimpleName(getRenammedField(pIField));

		astRewrite.replace(result, newSimpleName, null);

		return status;
	}

	private String getRefactoredName(String pName, String pPrefix) {
		String lResult = "";
		lResult = pPrefix + String.valueOf(pName.charAt(0)).toUpperCase()
				+ pName.substring(1);
		return lResult;
	}

	// public RefactoringStatus setClassName(String name) {
	// mName = name;
	// RefactoringStatus status = checkClassName(name,
	// JavaConventions.validateCompilationUnitName(name,
	// CompilerOptions.VERSION_1_3,
	// CompilerOptions.VERSION_1_3));
	// // status.merge(checkOverloading());
	// return status;
	// }

	public RefactoringStatus checkInput() {
		IStatus lIStatus = null;
		if (mICompilationUnit != null) {
			lIStatus = JavaConventions.validateCompilationUnitName(
					mICompilationUnit.getElementName(),
					CompilerOptions.VERSION_1_6, CompilerOptions.VERSION_1_6);
		} else if (mIPackageFragment != null) {
			lIStatus = JavaConventions.validatePackageName(
					mIPackageFragment.getElementName(),
					CompilerOptions.VERSION_1_6, CompilerOptions.VERSION_1_6);
		}
		return convertIStatus(lIStatus);
	}

	public void setUpdateReferences(boolean update) {
		mUpdateReferences = update;
	}

	public void setCompilationUnit(ICompilationUnit pICompilationUnit) {
		mICompilationUnit = pICompilationUnit;
		mICompilationUnits = new ArrayList<ICompilationUnit>();
		mICompilationUnits.add(mICompilationUnit);
	}

	public IJavaElement getCompilationUnit() {
		return mICompilationUnit;
	}

	private class MethodVisitor extends ASTVisitor {
		List<MethodDeclaration> methods = new ArrayList<MethodDeclaration>();
		ASTRewrite mASTRewrite;
		Map<String, String> mRefactoredVariables = new HashMap<String, String>();

		public MethodVisitor(ASTRewrite astRewrite) {
			mASTRewrite = astRewrite;
		}

		@Override
		public boolean visit(MethodDeclaration node) {
			List<Statement> lStatements = node.getBody().statements();
			for (Statement statement : lStatements) {
				if (statement instanceof VariableDeclarationStatement) {
					VariableDeclarationStatement lVariableDeclarationStatement = (VariableDeclarationStatement) statement;
					List<VariableDeclarationFragment> lVariableDeclarationFragments = lVariableDeclarationStatement
							.fragments();
					for (VariableDeclarationFragment variableDeclarationFragment : lVariableDeclarationFragments) {
						String name = variableDeclarationFragment.getName()
								.getIdentifier();

						if (hasToBeRenammed(name, LOCAL_VAR_PREFIX)) {
							AST ast = node.getAST();
							String lNewName = getRefactoredName(name,
									LOCAL_VAR_PREFIX);

							// Field declaration
							VariableDeclarationFragment fragment = ast
									.newVariableDeclarationFragment();

							fragment.setName(ast.newSimpleName(lNewName));

							Expression lExpression = variableDeclarationFragment
									.getInitializer();

							if (lExpression != null) {

								lookThrough(lExpression);

								Expression lCopiedExpression = (Expression) mASTRewrite
										.createCopyTarget(lExpression);

								fragment.setInitializer(lCopiedExpression);
							}

							mASTRewrite.replace(variableDeclarationFragment,
									fragment, null);
							mRefactoredVariables.put(name, lNewName);
						}
					}
				} else if (statement instanceof ExpressionStatement) {
					ExpressionStatement lExpressionStatement = (ExpressionStatement) statement;
					lookThrough(lExpressionStatement.getExpression());
				}
			}

			methods.add(node);
			return super.visit(node);
		}

		public Expression lookThrough(Expression pExpression) {
			Expression lResult = null;
			if (pExpression instanceof Assignment) {
				Assignment lAssignment = (Assignment) pExpression;
				lookThrough(lAssignment.getRightHandSide());
			} else if (pExpression instanceof PostfixExpression) {
				PostfixExpression lPostfixExpression = (PostfixExpression) pExpression;
				lookThrough(lPostfixExpression.getOperand());
			} else if (pExpression instanceof MethodInvocation) {
				MethodInvocation lMethodInvocation = (MethodInvocation) pExpression;
				List<Expression> lArguments = lMethodInvocation.arguments();
				for (Expression lExpression : lArguments) {
					lookThrough(lExpression);
				}
			} else if (pExpression instanceof InfixExpression) {
				InfixExpression lInfixExpression = (InfixExpression) pExpression;
				lookThrough(lInfixExpression.getLeftOperand());
				lookThrough(lInfixExpression.getRightOperand());
			} else if (pExpression instanceof SimpleName) {
				SimpleName lSimpleName = (SimpleName) pExpression;
				String lIdentifier = lSimpleName.getIdentifier();
				if (mRefactoredVariables.containsKey(lIdentifier)) {
					SimpleName lNewSimpleName = mASTRewrite.getAST()
							.newSimpleName(
									mRefactoredVariables.get(lIdentifier));
					mASTRewrite.replace(lSimpleName, lNewSimpleName, null);
					lResult = lNewSimpleName;
				}
			}
			return lResult;
		}

		public List<MethodDeclaration> getMethods() {
			return methods;
		}
	}

	private void fillListOfCompilationUnit(IPackageFragment pIPackageFragment,
			List<ICompilationUnit> pList) throws JavaModelException {
		for (ICompilationUnit lICompilationUnit : pIPackageFragment
				.getCompilationUnits()) {
			pList.add(lICompilationUnit);
		}
		IPackageFragmentRoot[] lIPackageFragmentRoots = mIPackageFragment
				.getJavaProject().getPackageFragmentRoots();
		List<IPackageFragment> lChildIPackageFragments = new ArrayList<IPackageFragment>();
		for (IPackageFragmentRoot lPackageFragmentRoot : lIPackageFragmentRoots) {
			IJavaElement[] lChildren = lPackageFragmentRoot.getChildren();
			for (IJavaElement lChild : lChildren) {
				if (lChild instanceof IPackageFragment) {
					String lPackageId = pIPackageFragment.getHandleIdentifier();
					if (!lChild.getHandleIdentifier().equals(lPackageId)
							&& lChild.getHandleIdentifier().startsWith(
									lPackageId)) {
						lChildIPackageFragments.add((IPackageFragment) lChild);
					}
				}
			}
		}
		for (IPackageFragment lPackageFragment : lChildIPackageFragments) {
			for (ICompilationUnit lICompilationUnit : lPackageFragment
					.getCompilationUnits()) {
				pList.add(lICompilationUnit);
			}
		}
	}

	public void setPackageFragment(IPackageFragment pIPackageFragment) {
		mIPackageFragment = pIPackageFragment;
		try {
			mICompilationUnits = new ArrayList<ICompilationUnit>();
			fillListOfCompilationUnit(pIPackageFragment, mICompilationUnits);
			System.out.println();
		} catch (JavaModelException e) {
			mICompilationUnits = new ArrayList<ICompilationUnit>();
		}

	}

	public IPackageFragment getPackageFragment() {
		return mIPackageFragment;
	}
}